﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MinesweeperModel
{
    public class Minesweeper : IMinesweeper
    {
        public int Columns { get; set; }
        public int Rows { get; set; }
        public int BombCount { get; set; }
        public Cell[,] Grid { get; set; }
        private int FlagCount;
        public enum Difficulty
        {
            Easy, Medium, Hard
        }

        public Minesweeper(int rows = 10, int cols = 10, int bombCount = 10)
        {
            Init(rows, cols, bombCount);
        }
        public Minesweeper(Difficulty difficulty)
        {
            Init(difficulty);
        }
        public void Init(Difficulty difficulty)
        {
            if (difficulty == Difficulty.Easy)
                Init(10, 10, 10);
            else if (difficulty == Difficulty.Medium)
                Init(20, 20, 50);
            else if (difficulty == Difficulty.Hard)
                Init(50, 50, 99);
        }
        public void Init(int rows = 10, int cols = 10, int bombCount = 10)
        {
            Rows = rows;
            Columns = cols;
            BombCount = bombCount;
            Grid = new Cell[Rows, Columns];

            for (var r = 0; r < Rows; r++)
            {
                for (var c = 0; c < Columns; c++)
                {
                    Grid[r,c] = new Cell();
                }
            }

            PlaceBombs();
            SetCellNeighboringBombCount();
        }

        private void SetCellNeighboringBombCount()
        {
            for (var r = 0; r < Rows; r++)
            {
                for (var c = 0; c < Columns; c++)
                {
                    if(Grid[r,c].NeighborBombCount == Cell.BOMB)continue;
                    for (var t = (c == 0 ? c : c - 1); t <= (t == Columns ? c : c + 1); t++)
                    {
                        //checks 3 Cells above current Cell
                        if (r > 0 && Grid[r - 1, t].NeighborBombCount == Cell.BOMB)
                                Grid[r, c].NeighborBombCount++;

                        //checks 3 Cells below current Cell
                        if (r < Rows-1 && Grid[r + 1, t].NeighborBombCount == Cell.BOMB)
                                Grid[r, c].NeighborBombCount++;
                        
                    }
                    //checks Cells on either side
                    if (c > 0 && Grid[r, c - 1].NeighborBombCount == Cell.BOMB)
                        Grid[r, c].NeighborBombCount++;
                    if (c < Columns-1 && Grid[r, c + 1].NeighborBombCount == Cell.BOMB)
                        Grid[r, c].NeighborBombCount++;
                }
            }

        }

        private void PlaceBombs()
        {
            var rand = new Random();
            for (int i = 0; i < BombCount; i++)
            {
                int x = rand.Next(0, Rows);
                int y = rand.Next(0, Columns);
                if (Grid[x, y].NeighborBombCount == Cell.BOMB)
                {
                    i--;
                    continue;
                }
                Grid[x, y].NeighborBombCount = Cell.BOMB;
            }
        }

        public void Flag(int r, int c)
        {
            if (Grid[r, c].isExposed)
                return;
            if(Grid[r,c].IsFlagged)
                FlagCount--;
            else
                FlagCount++;
            Grid[r, c].IsFlagged = !Grid[r, c].IsFlagged;
        }

        public void Expose(int r, int c)
        {
            Grid[r, c].isExposed = true;
            if (Grid[r, c].NeighborBombCount == 0)
            {
                if (r > 0 && !Grid[r - 1, c].isExposed) Expose(r - 1, c);
                if (c > 0 && !Grid[r, c - 1].isExposed) Expose(r, c - 1);
                if (r < Rows-1 && !Grid[r + 1, c].isExposed) Expose(r + 1, c);
                if (c < Columns-1 && !Grid[r, c + 1].isExposed) Expose(r, c + 1);
                if (r < Rows-1 && c < Columns-1 && !Grid[r + 1, c + 1].isExposed) Expose(r + 1, c + 1);
                if (r > 0 && c < Columns-1 && !Grid[r - 1, c + 1].isExposed) Expose(r - 1, c + 1);
                if (c > 0 && r < Rows-1 && !Grid[r + 1, c - 1].isExposed) Expose(r + 1, c - 1);
                if (r > 0 && c > 0 && !Grid[r - 1, c - 1].isExposed) Expose(r - 1, c - 1);
            }
        }

        public int BombsRemaining()
        {
            return BombCount - FlagCount;
        }
    }
}
